/* eslint-disable max-len */
const path = require('path');
const fs = require('fs-extra');
const utility = require('../../utility');
const StaticAnalyzeReport = require('./static-analyze-report');
const DefaultReport = require('./default-report');
const DataStreamReport = require('./datastream');
const CodeQualityMeasureReport = require('./codequalitymeasure');
const CoverageCollectReport = require('./coverageCollect');
const logger = require('./../../logger');
const PhoenixError = require('./../../phoenix-error');
const codeInstrumentations = require('./../../code-instrumentation');
const licenseModel = require('./../../license');

// 导出的测试报告类型
const exportReportType = {
  default: 1, // 默认测试报告
  codeQualityMeasure: 2, // 代码质量度量报告
  dataStream: 3, // 数据流报告
  staticAnalyze: 4, // 静态分析报告
  coverageCollect: 5, // 覆盖率收集报告
};
function getReportInstance(versionType, reportType = exportReportType.default) {
  let report;
  switch (reportType) {
    case exportReportType.codeQualityMeasure: {
      report = CodeQualityMeasureReport;
      break;
    }
    case exportReportType.dataStream: {
      report = DataStreamReport;
      break;
    }
    case exportReportType.staticAnalyze: {
      let reportAnalyzeTemplate = './enabled-analyze-report';
      if (global.config.path.enabledAnalyzeReport) {
        reportAnalyzeTemplate = `./${global.config.path.enabledAnalyzeReport}`;
      }
      try {
        report = utility.requireUncached(path.join(__dirname, reportAnalyzeTemplate));
      } catch (err) {
        if (err.code !== 'ENOENT') {
          logger.error({}, err);
        }
        logger.debug('use static analyze default template');
        report = StaticAnalyzeReport;
      }
      break;
    }
    case exportReportType.coverageCollect: {
      report = CoverageCollectReport;
      break;
    }
    case exportReportType.default:
    default: {
      try {
        let reportTemplate = './enabled-report';
        if (global.config.path.enabledReport) {
          reportTemplate = `./${global.config.path.enabledReport}`;
        }
        report = utility.requireUncached(path.join(__dirname, reportTemplate));
        if (!report.versionTypeSupport(versionType)) {
          report = DefaultReport;
        }
      } catch (err) {
        if (err.code !== 'ENOENT') {
          logger.error({}, err);
        }
        report = DefaultReport;
      }
      break;
    }
  }
  return report;
}

/**
 * 获取测试报告
 * @param {String} projectVersionId 项目版本id
 * @param {Object} locale 国际化
 * @param {Object} projectVersion 项目版本
 * @param {Object} project 项目
 * @param {Object} creator 用户
 * @param {string} format 文件格式docx｜pdf
 * @param {boolean} complete 是否输出未赋值变量 仅default template有效
 * @param {number} reportType 测试报告类型
 * @param {Object} license 许可证
 * @return {Promise}
 */
function getReport(
  projectVersionId,
  locale,
  projectVersion = null,
  project = null,
  creator = null,
  format = null,
  complete = false,
  reportType,
  license,
) {
  const Report = getReportInstance(projectVersion.versionType, reportType ? parseInt(reportType, 10) : exportReportType.default);
  if (licenseModel.isEducationVersion(license)) {
    if (!license.testReport) {
      throw new PhoenixError('invalid request', 'no authority to download all report');
    }
    if ((!reportType || parseInt(reportType, 10) === exportReportType.default) && license.testReport.indexOf(1) < 0 && license.testReport.indexOf(2) < 0) {
      throw new PhoenixError('invalid request', 'no authority to download test report');
    }
    if (parseInt(reportType, 10) === exportReportType.codeQualityMeasure && license.testReport.indexOf(3) < 0) {
      throw new PhoenixError('invalid request', 'no authority to download codeQualityMeasure report');
    }
    if (parseInt(reportType, 10) === exportReportType.dataStream && license.testReport.indexOf(4) < 0) {
      throw new PhoenixError('invalid request', 'no authority to download dataStream report');
    }
  }
  const testReport = licenseModel.isEducationVersion(license) ? license.testReport : null;
  return new Report(projectVersionId, locale, projectVersion, project, creator, null, format, complete, testReport);
}

function getStaticAnalyzeReport(
  projectVersionId,
  locale,
  projectVersion = null,
  project = null,
  creator = null,
  format = 'docx',
  filters = {},
  reportType,
  reportCategory,
  license,
) {
  reportType = reportType ? parseInt(reportType, 10) : exportReportType.staticAnalyze;
  const Report = getReportInstance(projectVersion.versionType, reportType === exportReportType.default ? exportReportType.staticAnalyze : reportType);
  if (licenseModel.isEducationVersion(license)) {
    if (!license.testReport) {
      throw new PhoenixError('invalid request', 'no authority to download all report');
    }
    if (reportType === exportReportType.default && license.testReport.indexOf(1) < 0 && license.testReport.indexOf(2) < 0) {
      throw new PhoenixError('invalid request', 'no authority to download test report');
    }
    if (reportType === exportReportType.codeQualityMeasure && license.testReport.indexOf(3) < 0) {
      throw new PhoenixError('invalid request', 'no authority to download codeQualityMeasure report');
    }
    if (reportType === exportReportType.dataStream && license.testReport.indexOf(4) < 0) {
      throw new PhoenixError('invalid request', 'no authority to download dataStream report');
    }
  }
  const testReport = licenseModel.isEducationVersion(license) ? license.testReport : null;
  return new Report(projectVersionId, locale, projectVersion, project, creator, null, format, filters, reportCategory, null, testReport);
}

async function getCodeInstrumentationReport(
  codeInsAndResults,
  locale,
  projectVersion,
  project,
  creator,
  format,
  complete,
  includeTestcase,
) {
  const {
    filesMap,
    functionsMap,
    testcasesMap,
    mode,
  } = await codeInstrumentations.analyzeResults(codeInsAndResults, projectVersion);
  let Report;
  projectVersion.mode = mode;
  switch (mode) {
    case 'targetMachine':
      Report = getReportInstance(projectVersion.versionType);
      break;
    case 'codeInstrumentation':
      Report = getReportInstance(projectVersion.versionType);
      if (!Report.codeInstrumentationSupport()) {
        Report = getReportInstance(projectVersion.versionType, exportReportType.coverageCollect);
      }
      break;
    case 'mixed':
    default:
      Report = getReportInstance(projectVersion.versionType, exportReportType.coverageCollect);
      break;
  }
  projectVersion.codeInsAndResults = codeInsAndResults;
  const reportInstance = new Report(projectVersion._id, locale, projectVersion, project, creator, null, format, complete, null, includeTestcase);
  reportInstance.setTargetMachineDataSource({ filesMap, functionsMap, testcasesMap });
  return reportInstance;
}

// 是否启用自定义模版
/* note:
   1:如果enabled-report不存在，则返回false
   2:如果enabled-report存在且上传的模版为default模版，则返回false
   3:如果enabled-report存在且上传的模版为非default模版，则返回true
*/
async function hasEnabledReport() {
  const dir = path.join(__dirname, './enabled-report');
  if (!(await fs.pathExists(dir))) {
    return false;
  }
  const p = path.join(__dirname, './enabled-report/template.info.json');
  if (await fs.pathExists(p)) {
    const info = utility.requireUncached(p);
    return !(info && info.isDefault);
  }
  return true;
}

// 不改变原始值的情况下删除空字段
function removeNullKeys(obj) {
  const ret = {};
  Object.keys(obj).forEach((k) => {
    if (obj[k]) {
      ret[k] = obj[k];
    }
  });
  return ret;
}

async function getTestReportFormats() {
  const defaultInfo = utility.requireUncached(path.join(__dirname, 'default-report/template.info.json'));
  const uploadedPath = path.join(__dirname, './enabled-report/template.info.json');
  if (!await fs.pathExists(uploadedPath)) {
    return removeNullKeys(defaultInfo.reportFormats);
  }
  const enabledInfo = utility.requireUncached(uploadedPath);
  const combinedFormats = { ...defaultInfo.reportFormats, ...enabledInfo.reportFormats };
  return removeNullKeys(combinedFormats);
}

async function getAnalyzeReportFormats() {
  const defaultInfo = utility.requireUncached(path.join(__dirname, 'static-analyze-report/template.info.json'));
  const uploadedPath = path.join(__dirname, './enabled-analyze-report/template.info.json');
  if (!await fs.pathExists(uploadedPath)) {
    return removeNullKeys(defaultInfo.reportFormats);
  }
  const enabledInfo = utility.requireUncached(uploadedPath);
  const combinedFormats = { ...defaultInfo.reportFormats, ...enabledInfo.reportFormats };
  return removeNullKeys(combinedFormats);
}

/**
 * Export model definition object.
 */
module.exports = {
  getReport,
  getStaticAnalyzeReport,
  getCodeInstrumentationReport,
  hasEnabledReport,
  exportReportType,
  getTestReportFormats,
  getAnalyzeReportFormats,
};
